<template>
  <nav class="side-menu">
    <div v-if="filteredGroup" class="group">
      <h4>{{ filteredGroup.name }}</h4>
      <ul class="menu-root">
        <MenuItem
          v-for="item in filteredGroup.children"
          :key="item.url || item.name"
          :item="item"
          :level="0"
        />
      </ul>
    </div>
    <div v-else>
      <p>No menu available</p>
    </div>
  </nav>
</template>

<script setup lang="ts">
import { computed, h, defineComponent } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useMenuStore } from '../stores/menu'
import { useAuthStore } from '../stores/auth'
import { storeToRefs } from 'pinia'
import { watch } from 'vue'

const router = useRouter()
const route = useRoute()
const menu = useMenuStore()
const auth = useAuthStore()
const { activeTop, activeItem } = storeToRefs(menu)
const { menus } = storeToRefs(auth)

const currentGroup = computed(() => {
  if (!menus.value || menus.value.length === 0) return null
  return menus.value.find((m: any) => m.name === activeTop.value) || menus.value[0]
})

// Filter out items where is_function === 1 recursively
const filteredGroup = computed(() => {
  const g = currentGroup.value
  if (!g) return null

  function cloneAndFilter(node: any) {
    if (!node) return null
    // skip function items
    if (node.is_function === 1) return null
    const copy: any = { ...node }
    if (Array.isArray(copy.children) && copy.children.length > 0) {
      const ch = copy.children.map((c: any) => cloneAndFilter(c)).filter((x: any) => x != null)
      copy.children = ch
    }
    return copy
  }

  const res = cloneAndFilter(g)
  // if group exists but has no visible children, treat as empty
  if (!res) return null
  if (Array.isArray(res.children) && res.children.length === 0) return null
  return res
})

// If currentGroup is empty but menus exist, try to locate which top menu contains current route
// and set activeTop accordingly so the side menu appears after refresh.
function normalize(p: string | undefined) {
  if (!p) return ''
  try { p = decodeURI(p) } catch (e) {}
  if (!p.startsWith('/')) p = '/' + p
  if (p.length > 1 && p.endsWith('/')) p = p.slice(0, -1)
  return p
}

function pathMatches(menuUrl: string | undefined, path: string): boolean {
  const mu = normalize(menuUrl)
  const p = normalize(path)
  if (!mu) return false
  if (mu === p) return true
  if (p.endsWith(mu) || mu.endsWith(p)) return true
  const pSeg = p.split('/').filter(Boolean)
  const muSeg = mu.split('/').filter(Boolean)
  if (pSeg.length && muSeg.length && pSeg[pSeg.length-1] === muSeg[muSeg.length-1]) return true
  return false
}

function findTopForPath(items: any[], path: string): any | null {
  for (const item of items || []) {
    if (!item) continue
    if (pathMatches(item.url, path)) return item
    if (item.children && item.children.some((c: any) => pathMatches(c.url, path))) return item
    if (item.children && item.children.length) {
      const childRes = findTopForPath(item.children, path)
      if (childRes) return item
    }
  }
  return null
}

watch([menus, () => route.path], () => {
  try {
    if (!menus.value || menus.value.length === 0) return
    const g = currentGroup.value
    if (g && g.children && g.children.length > 0) return // already has children

    // try to find the top menu that should correspond to current route
    const found = findTopForPath(menus.value || [], route.path)
    if (found) {
      // set active top and ensure sidebar shown
      try { menu.setActiveTop(found.name) } catch (e) {}
      try { menu.setShowSidebar(true) } catch (e) {}
    }
  } catch (e) { /* ignore */ }
}, { immediate: true })

function go(path: string) {
  if (!path) return
  router.push(path)
}

// Recursive menu item component using render function so it can call itself
const MenuItem = defineComponent({
  name: 'MenuItem',
  props: {
    item: { type: Object as () => any, required: true },
    level: { type: Number, required: false, default: 0 }
  },
  setup(props) {
    return () => {
      const item = props.item
      const hasChildren = item.children && item.children.length > 0
      const padding = `${props.level * 12}px`

      return h('li', { class: ['menu-item', { active: (activeItem.value ? (activeItem.value === (item.url || '') || activeItem.value === item.name || (item.url ? pathMatches(item.url, activeItem.value) : false)) : pathMatches(item.url, route.path)) }], style: { paddingLeft: padding } }, [
        h('div', {
          class: ['menu-row'],
          onClick: () => {
            // remember last clicked item (use url if available, otherwise use name)
            try { menu.setActiveItem(item.url ? item.url : item.name) } catch (e) {}
            if (item.url) {
              go(item.url)
            }
          }
        }, item.name),
        hasChildren
          ? h('ul', { class: 'menu-children' }, item.children.map((ch: any) => h(MenuItem, { item: ch, level: props.level + 1 })))
          : null
      ])
    }
  }
})
</script>

<style scoped>
.side-menu { padding: 12px; }
.side-menu .group { margin-bottom: 16px }
.side-menu h4 { margin: 0 0 8px 0; font-size: 13px; color:#333 }
.side-menu ul { list-style:none; padding:0; margin:0 }
.side-menu li { padding:8px 10px; border-radius:4px; cursor:pointer; color:#2c3e50 }
.side-menu li.active { background:#e6f0ff;color:#e6a23c  }
.side-menu li.active .menu-row { color: #e6a23c }
.side-menu li:hover { background:#f5f7fa }

/* styles for recursive menu */
.menu-root { padding-left: 0 }
.menu-item { padding: 0; margin: 4px 0 }
.menu-row { padding:8px 10px; border-radius:4px; cursor:pointer; color:inherit }
.menu-row.active { background:#e6f0ff }
.menu-row:hover { background:#f5f7fa }
.menu-children { margin-top: 4px }
</style>